package com.duguo.dynamicmvc.factory.processor.register;

import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.duguo.dynamicmvc.factory.ControllerBuilder;
import com.duguo.dynamicmvc.factory.processor.controller.ControllerNameBuilder;
import com.duguo.dynamicmvc.factory.utils.BeanUtils;
import com.duguo.dynamicmvc.view.View;


public class RegisterProcessorImpl implements RegisterProcessor{

	static Log log = LogFactory.getLog(RegisterProcessorImpl.class);

	ControllerNameBuilder _controllerNameBuilder;
	
    public void registerController(Object parentController, String controllerName, Object controllerInstance) {
        String remainControllerName = null;
        controllerName = _controllerNameBuilder.getNormalizedName(controllerName);
        if (_controllerNameBuilder.isMultiLevelName(controllerName)) {
            remainControllerName = _controllerNameBuilder.getRemainLevelName(controllerName);
            controllerName = _controllerNameBuilder.getFirstLevelName(controllerName);
        }

        Map<String, Object> registedControllers = BeanUtils.getFieldValue(parentController, "registedControllers", Map.class);
        Object existController = getExistController(parentController, controllerName, registedControllers);

        if (existController == null && remainControllerName == null) {
            registedControllers.put(controllerName, controllerInstance);
        } else if (existController != null && remainControllerName == null) {
            log.warn("The controller " + controllerName + " already exist in " + parentController.getClass().getName() + " and won't register again");
        } else if (existController != null && isMultiActionController(existController)) {
            registerControllerBean(existController, remainControllerName, controllerInstance);
        } else {
            ControllerBuilder controllerBuilder = BeanUtils.getFieldValue(parentController, "controllerBuilder", ControllerBuilder.class);            
            registerInNewMultiActionController(parentController, controllerName, controllerInstance, remainControllerName, registedControllers, existController,controllerBuilder);
        }
    }


    public void registerView(Object parentController, String controllerName, View view) {
        try {
            ControllerBuilder controllerBuilder = BeanUtils.getFieldValue(parentController, "controllerBuilder", ControllerBuilder.class);
            
            Class staticControllerClass = controllerBuilder.getProcessorHolder().getControllerProcessor().getControllerMultiActionCreator().getStaticControllerClass(parentController, controllerName,controllerBuilder);
            Object ctrlInstance = staticControllerClass.newInstance();
            controllerBuilder.getProcessorHolder().getViewProcessor().bindView(parentController,ctrlInstance,view);
            BeanUtils.setFieldValue(ctrlInstance, "controller", parentController);
            registerControllerBean(parentController, controllerName, ctrlInstance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public void registerControllerView(Object parentController, String controllerName, View view) {
        Object[] args = new Object[]{controllerName, view};
        BeanUtils.invoteMethod(parentController, "registerView", args);
    }

    public void registerControllerBean(Object parentController, String controllerName, Object controllerBean) {
    	if(BeanUtils.hasField(parentController, "registedControllers")){
    		Object[] args = new Object[]{controllerName, controllerBean};
	        BeanUtils.invoteMethod(parentController, "registerController", args);
        }else if(BeanUtils.hasField(parentController, "controller")){
        	BeanUtils.setFieldValue(parentController, "controller", controllerBean);
        }else {
        	throw new RuntimeException("Cannot register controller bean "+ controllerName);
        }
    }


    void registerInNewMultiActionController(Object parentController, String controllerName, Object controllerInstance, String remainControllerName, Map<String, Object> registedControllers, Object existController, ControllerBuilder controllerBuilder) {
        try {
            Object newController = controllerBuilder.getProcessorHolder().getControllerProcessor().getControllerMultiActionCreator().createGeneralMultiActionController(parentController,controllerName,controllerBuilder);
            registedControllers.put(controllerName, newController);
            if (existController != null) {
                registerControllerBean(newController, "index", existController);
            }
            registerControllerBean(newController, remainControllerName, controllerInstance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    Object getExistController(Object parentController, String controllerName, Map<String, Object> registedControllers) {
        Object existController = null;
        Object dynamicController = BeanUtils.tryToGetFieldValue(parentController, "dynamicController", Object.class);
        if (dynamicController != null) {
            String dynamicControllerName = _controllerNameBuilder.getControllerPath(dynamicController.getClass().getName());
            dynamicControllerName=_controllerNameBuilder.getLastLevelName(dynamicControllerName);
            if (dynamicControllerName.equals(controllerName)) {
                existController = dynamicController;
            }
        }
        if (existController == null) {
            existController = registedControllers.get(controllerName);
        }
        return existController;
    }

    boolean isMultiActionController(Object existController) {
        Map registedControllers = BeanUtils.getFieldValue(existController, "registedControllers", Map.class);
        return registedControllers != null;
    }


	public ControllerNameBuilder getControllerNameBuilder() {
		return _controllerNameBuilder;
	}


	public void setControllerNameBuilder(ControllerNameBuilder controllerNameBuilder) {
		_controllerNameBuilder = controllerNameBuilder;
	}
}
